package com.jccfc.spi;

import java.util.concurrent.ConcurrentHashMap;

/* *
 * SPI加载器
 * <p>说明</p>
 * <li></li>
 * @Author DuanYong 
 * @Since 2019/4/6 22:29
 * @Version 1.0
 */
public final class SpiLoader {
    /**对象缓存：类名称->类对象*/
    private static final Map<String, Object> CACHE = new ConcurrentHashMap<>();
    /**
     * 清空缓存
     * <p>说明:</p>
     * <li></li>
     * @Author DuanYong
     * @Since 2019/4/6 22:29
     */
    public static void clear() {
        CACHE.clear();
    }
    /**
     * 根据类类型从缓存中加载类对象
     * <p>说明:</p>
     * <li></li>
     * @Author DuanYong
     * @Since 2019/4/6 21:40
     * @param clazz 类类型
     * @return T 类对象
     */
    public static <T> T load(Class<T> clazz) {
        return load(clazz, null);
    }
    /**
     * 根据类类型，类名称从缓存中加载类对象
     * <p>说明:</p>
     * <li>如果缓存不存在，则调用服务提供者加载工具加载，并缓存</li>
     * @Author DuanYong
     * @Since 2019/4/6 21:45
     * @param clazz 类类型
     * @param name 类名称
     * @return T 类对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T load(Class<T> clazz, String name) {
        String key = clazz.getName();
        Object o = CACHE.get(key);
        if (o == null) {
            T t = doLoad(clazz, name);
            if (t != null) {
                CACHE.put(key, t);
                return t;
            }
        } else if (clazz.isInstance(o)) {
            return (T) o;
        }
        return doLoad(clazz, name);
    }
    /**
     * 执行加载
     * <p>说明:</p>
     * <li></li>
     * @Author DuanYong
     * @Since 2019/4/6 21:50
     * @param clazz 类类型
     * @param name 类名称
     * @return T 类对象
     */
    private static <T> T doLoad(Class<T> clazz, String name) {
        ServiceLoader<T> factories = ServiceLoader.load(clazz);
        T t = filterByName(factories, name);

        if (t == null) {
            factories = ServiceLoader.load(clazz, SpiLoader.class.getClassLoader());
            t = filterByName(factories, name);
        }

        if (t != null) {
            return t;
        } else {
            throw new IllegalStateException("Cannot find META-INF/services/" + clazz.getName() + " on classpath");
        }
    }
    /**
     * 根据类名称查找对应的类对象
     * <p>说明:</p>
     * <li>如果名称为空，则根据Spi注解配置的order降序排序，取第一个</li>
     * @Author DuanYong
     * @Since 2019/4/6 21:58
     * @param factories 服务提供者加载工具
     * @param name 类名称
     * @return T 类对象
     */
    private static <T> T filterByName(ServiceLoader<T> factories, String name) {
        Iterator<T> it = factories.iterator();
        if (name == null) {
            List<T> list = new ArrayList<T>(2);
            while (it.hasNext()) {
                list.add(it.next());
            }
            if (list.size() > 1) {
                list.sort((o1, o2) -> {
                    Spi spi1 = o1.getClass().getAnnotation(Spi.class);
                    Spi spi2 = o2.getClass().getAnnotation(Spi.class);
                    int order1 = spi1 == null ? 0 : spi1.order();
                    int order2 = spi2 == null ? 0 : spi2.order();
                    return order1 - order2;
                });
            }
            if (list.size() > 0){return list.get(0);}
        } else {
            while (it.hasNext()) {
                T t = it.next();
                if (name.equals(t.getClass().getName()) ||
                        name.equals(t.getClass().getSimpleName())) {
                    return t;
                }
            }
        }
        return null;
    }
}
